package org.wsff.tools.api.gateway;

import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;

import org.wsff.tools.api.gateway.core.Gateway;
import org.wsff.tools.api.gateway.error.Assert;
import org.wsff.tools.api.gateway.error.GatewayException;
import org.wsff.tools.api.gateway.model.BaseRequest;
import org.wsff.tools.api.gateway.model.BaseResponse;

/**
 * Gateway 包装类
 *
 * @author ryan
 * @version Id: AbstractApiGateway.java, v 0.1 2022-01-18 11:25 ryan Exp $$
 */
@Slf4j
public abstract class AbstractApiGateway {

    /** 服务网关 */
    @Resource
    private Gateway<BaseRequest, BaseResponse> gateway;

    /**
     * 网关接口
     *
     * @param request 请求参数
     * @param name proxy name
     * @param clazz 返回值类型
     * @param <GIn> 入参泛型
     * @param <GOut> 响应泛型
     * @return 响应
     */
    protected <GIn extends BaseRequest, GOut extends BaseResponse> GOut execute(GIn request, String name, Class<GOut> clazz) {
        try {
            baseValidate(request, name);
            if (isOpenLog(name)) {
                log.info("[{}]: the request data is {} ", name, request.toString());
            }
            long start = System.currentTimeMillis();

            GOut response = (GOut) gateway.invoke(request, name);
            if (isOpenLog(name)) {
                log.info("[{}]: time:{},the response data is {}", new Object[] { name, (System.currentTimeMillis() - start), response.toString() });
            }
            return response;
        } catch (GatewayException e) {
            return createErrorResponse(request, e, clazz);
        }
    }

    /**
     * 是否开启日志
     *
     * @param name proxy name
     * @return 是否
     */
    protected boolean isOpenLog(String name) {
        return true;
    }

    /**
     * 基础验证
     * 
     * @param request 请求
     * @param name 代理服务名称
     * @throws GatewayException 异常
     */
    protected <GIn extends BaseRequest> void baseValidate(GIn request, String name) throws GatewayException {
        try {
            Assert.notNullValidate(request, "Request cannot be null");
            Assert.notNullValidate(name, "ProxyEnum cannot be null");
        } catch (IllegalArgumentException e) {
            throw new GatewayException(e);
        }
    }

    /**
     * 根据APIException创建Error Response
     *
     * @param e 㕈
     * @return 响应
     */
    public <TIn extends BaseRequest, TOut extends BaseResponse> TOut createErrorResponse(TIn request, GatewayException e, Class<TOut> clazz) {
        try {
            TOut response = clazz.newInstance();
            response.setCode(e.getErrorCode());
            response.setMessage(e.getMessage());
            response.setSuccess(false);
            response.setTracerId(request.getTracerId());
            return response;
        } catch (Exception ex) {
            log.error("gateway create error response exception,message:" + e.getMessage(), e);
            throw new RuntimeException(ex);
        }
    }

    /**
     * Gets the value of gateway.
     *
     * @return the value of gateway
     */
    public Gateway<BaseRequest, BaseResponse> getGateway() {
        return gateway;
    }

    /**
     * Sets the gateway. *
     * <p>You can use getGateway() to get the value of gateway</p >
     * @param gateway gateway
     */
    public void setGateway(Gateway<BaseRequest, BaseResponse> gateway) {
        this.gateway = gateway;
    }
}
